/**
  ******************************************************************************
  * @file    can_bootloader.c
  * $Author: wdluo $
  * $Revision: 17 $
  * $Date:: 2012-07-06 11:16:48 +0800 #$
  * @brief   基于CAN总线的Bootloader程序.
  ******************************************************************************
  * @attention
  *
  *<h3><center>&copy; Copyright 2009-2012, ViewTool</center>
  *<center><a href="http:\\www.viewtool.com">http://www.viewtool.com</a></center>
  *<center>All Rights Reserved</center></h3>
  * 
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "can_boot.h"
#include "crc16.h"
#include "delay.h"
#if ENCRYPT
#include "aes.h"
#endif
/* Private typedef -----------------------------------------------------------*/
typedef  void (*pFunction)(void);

/* Private define ------------------------------------------------------------*/

/* Base address of the Flash sectors */
#define ADDR_FLASH_SECTOR_0     ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */
#define ADDR_FLASH_SECTOR_1     ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */
#define ADDR_FLASH_SECTOR_2     ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */
#define ADDR_FLASH_SECTOR_3     ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */
#define ADDR_FLASH_SECTOR_4     ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */
#define ADDR_FLASH_SECTOR_5     ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */
#define ADDR_FLASH_SECTOR_6     ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */
#define ADDR_FLASH_SECTOR_7     ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */
#define ADDR_FLASH_SECTOR_8     ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */
#define ADDR_FLASH_SECTOR_9     ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */
#define ADDR_FLASH_SECTOR_10    ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */
#define ADDR_FLASH_SECTOR_11    ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbytes */ 
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/


/**
 * @brief  获取固件升级标志
 * @return 固件升级标志状态
 * @retval 1 固件升级标志有效
 * @retval 0 固件升级标志无效
 */
uint8_t CAN_BOOT_GetProgRequest(void)
{
  //读取请求固件升级标志，需要自己实现
  if(*((uint32_t *)BOOT_REQ_FLAG_ADDR)==BOOT_REQ_FLAG){
    return 1;
  }else{
    return 0;
  }
}
/**
 * @brief  将固件升级标志置位
 */
void CAN_BOOT_SetProgRequest(void)
{
  __set_PRIMASK(1);//关闭中断
  FLASH_Unlock();
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 
  FLASH_EraseSector(GetSector(ADDR_FLASH_SECTOR_1), VoltageRange_3);//同时也清除APP有效标志
  FLASH_ProgramWord(BOOT_REQ_FLAG_ADDR,BOOT_REQ_FLAG);//将固件升级标志置位
  FLASH_Lock();
  __set_PRIMASK(0);//开启中断
}

/**
 * @brief  将固件升级标志复位
 */
void CAN_BOOT_ResetProgRequest(void)
{
  uint32_t AppValidFlag = *((uint32_t *)APP_VALID_FLAG_ADDR);
  __set_PRIMASK(1);//关闭中断
  FLASH_Unlock();
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 
  FLASH_EraseSector(GetSector(ADDR_FLASH_SECTOR_1), VoltageRange_3);
  FLASH_ProgramWord(APP_VALID_FLAG_ADDR,AppValidFlag);
  FLASH_Lock();
  __set_PRIMASK(0);//开启中断
}

/**
 * @brief  将固件升级标志置位
 */
void CAN_BOOT_SetAppValid(void)
{
  __set_PRIMASK(1);//关闭中断
  FLASH_Unlock();
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 
  FLASH_ProgramWord(APP_VALID_FLAG_ADDR,APP_VALID_FLAG);
  FLASH_Lock();
  __set_PRIMASK(0);//开启中断
}

/**
 * @brief 软件复位程序 
 */
void CAN_BOOT_Reset(void)
{
  __set_FAULTMASK(1);//关闭中断
  NVIC_SystemReset();
}
/**
 * @brief 执行APP程序 
 */
void CAN_BOOT_ExeApp(void)
{
  CAN_BOOT_JumpToApplication(APP_START_ADDR);
}
/**
 * @brief 擦除应用程序
 * @return 擦除状态
 * @retval 0 成功
 * @retval 1 失败
 */
uint8_t CAN_BOOT_EraseApp(void)
{
  return CAN_BOOT_ErasePage();
}

/**
 * @brief 判断APP应用程序是否有效
 * @return 应用程序有效状态
 * @retval 0 无效
 * @retval 1 有效
 */
uint8_t CAN_BOOT_CheckApp(void)
{
  return 1;
}

/**
 * @brief  将数据写入Flash
 * @param  Addr 数据起始地址
 * @param  pData 数据指针
 * @param  DataLen 写入数据字节数
 * @return 写入状态
 * @retval 0 成功
 * @retval 1 失败
 */
uint8_t CAN_BOOT_WriteDataToFlash(uint32_t Addr,uint8_t *pData,uint32_t DataLen)
{
	return CAN_BOOT_ProgramDatatoFlash(Addr,pData,DataLen);
}

/**
  * @brief  Gets the sector of a given address
  * @param  None
  * @retval The sector of a given address
  */
uint32_t GetSector(uint32_t Address)
{
  uint32_t sector = 0;
  
  if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
  {
    sector = FLASH_Sector_0;  
  }
  else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
  {
    sector = FLASH_Sector_1;  
  }
  else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
  {
    sector = FLASH_Sector_2;  
  }
  else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
  {
    sector = FLASH_Sector_3;  
  }
  else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
  {
    sector = FLASH_Sector_4;  
  }
  else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
  {
    sector = FLASH_Sector_5;  
  }
  else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
  {
    sector = FLASH_Sector_6;  
  }
  else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
  {
    sector = FLASH_Sector_7;  
  }
  else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
  {
    sector = FLASH_Sector_8;  
  }
  else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
  {
    sector = FLASH_Sector_9;  
  }
  else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
  {
    sector = FLASH_Sector_10;  
  }
  else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11))*/
  {
    sector = FLASH_Sector_11;  
  }

  return sector;
}

/**
  * @brief  将数据烧写到指定地址的Flash中 。
  * @param  Address Flash起始地址。
  * @param  Data 数据存储区起始地址。
  * @param  DataNum 数据字节数。
  * @retval 数据烧写状态。
  */
uint8_t CAN_BOOT_ProgramDatatoFlash(uint32_t StartAddr,uint8_t *pData,uint32_t DataNum) 
{
  FLASH_Status FLASHStatus=FLASH_COMPLETE;

  uint16_t *pDataTemp=(uint16_t *)pData;
  uint32_t i;
  __set_PRIMASK(1);//关闭中断
  FLASH_Unlock();
  if(StartAddr<APP_VALID_FLAG_ADDR){
    return 2;
  }
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 

  for(i=0;i<(DataNum>>1);i++)
  {
    FLASHStatus = FLASH_ProgramHalfWord(StartAddr, *pDataTemp);
    if (FLASHStatus == FLASH_COMPLETE){
      StartAddr += 2;
      pDataTemp++;
    }else{ 
      FLASH_Lock();
      __set_PRIMASK(0);//开启中断
      return 1;
    }
  }
  FLASH_Lock();
  __set_PRIMASK(0);//开启中断
  return	0;
}
/**
  * @brief  擦出指定扇区区间的Flash数据 。
  * @param  StartPage 起始扇区地址
  * @param  EndPage 结束扇区地址
  * @retval 扇区擦出状态  
  */
uint8_t CAN_BOOT_ErasePage(void)
{
  FLASH_Status FLASHStatus=FLASH_COMPLETE;
  uint32_t StartSector, EndSector;
  uint32_t SectorCounter=0;
  __set_PRIMASK(1);//关闭中断
  FLASH_Unlock();
  /* Get the number of the start and end sectors */
  StartSector = GetSector(ADDR_FLASH_SECTOR_2);
  EndSector = GetSector(ADDR_FLASH_SECTOR_6);
  /* Clear pending flags (if any) */  
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 
  for(SectorCounter = StartSector; SectorCounter <= EndSector; SectorCounter += 8){
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
       be done by word */ 
    FLASHStatus = FLASH_EraseSector(SectorCounter, VoltageRange_3);
    if (FLASHStatus != FLASH_COMPLETE)
    {
      FLASH_Lock();
      __set_PRIMASK(0);//开启中断
      return 1;
    }
  }
  FLASH_Lock();
  __set_PRIMASK(0);//开启中断
  return 0;
}

/**
 * @brief  执行指定地址处程序
 * @param  Addr 程序起始地址
 */
void CAN_BOOT_JumpToApplication(uint32_t Addr)
{
  pFunction JumpToApp;
  __IO uint32_t JumpAddress; 
  __set_PRIMASK(1);//关闭全局中断，注意，必须在APP中打开全局中断，否则可能会导致APP中断程序不正常
  if (((*(__IO uint32_t*)Addr) & 0x2FFE0000 ) == 0x20000000)
  { 
    JumpAddress = *(__IO uint32_t*) (Addr + 4);
    JumpToApp = (pFunction) JumpAddress;
    __set_MSP(*(__IO uint32_t*)Addr);
    JumpToApp();
  }
}



